
package com.mongoproject.database;
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.parsers.*;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;

/**
 * @author Camaria Bevavy
 *	this class defines methods to be used for the view metadata
 *	create  and update the metadata file
 */
public class ViewMetadata {

	public ViewMetadata(){
		
	}
	
	/**
	 * check if metadata file exists or not
	 * @return true if exist, false otherwise
	 */
	private boolean isExist(){
		boolean isexist = false;
		File met = new File("metadata.xml");
		if(met.exists()){
			isexist = true;
		}
		return isexist;
	}
	
	/**
	 * create metadata file if it does not exist
	 */
	private void buildMetaFile(){
		
		DocumentBuilder docbuilder = null;
		Transformer transform = null;
		Document new_doc = null;
		
		try {
			DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
			docbuilder = docfactory.newDocumentBuilder();
		}
		catch(ParserConfigurationException e){
			e.printStackTrace();
		}
		
		new_doc = docbuilder.newDocument();
		//create big parent
		Element root = new_doc.createElement("metadata");
		new_doc.appendChild(root);
		
		try{
			TransformerFactory tFactory = TransformerFactory.newInstance();
			transform = tFactory.newTransformer();
			transform.setOutputProperty(OutputKeys.INDENT, "yes");
		}
		catch(TransformerConfigurationException e){
			e.printStackTrace();
		}
		
		if(transform != null){
			DOMSource xml_source = new DOMSource(new_doc);			
			
			String filename = "metadata.xml";
			File xml_file = new File(filename);
			StreamResult xml_doc = new StreamResult(xml_file);
			
			try{
				transform.transform(xml_source, xml_doc);
			}
			catch(TransformerException e){
				e.printStackTrace();
			}
		}
		
		
	}


	/**
	 * Given a query, look inside the meta to check if the same query exists
	 * @param viewName
	 * @param query
	 */
	public String findViewMeta(String collectionName, String query){
		//check if file exist first
		
		String viewfile = null;
		if(!isExist()){
			buildMetaFile();
		}
		else{
			DocumentBuilder docbuilder = null;
			Document new_doc = null;
			
			try {
				DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
				docbuilder = docfactory.newDocumentBuilder();
			}
			catch(ParserConfigurationException e){
				e.printStackTrace();
			}
			
			new_doc = docbuilder.newDocument();
			
			String path = "metadata.xml";		
			File xmlfile = new File(path);
			
			try{
				new_doc = docbuilder.parse(xmlfile);
			}
			catch(Exception e){
				e.printStackTrace();
			}
			
			Node root = new_doc.getFirstChild();
			//System.out.println("root element "+root.getNodeName());
						
			NodeList views = root.getChildNodes(); //get all the views
						
			for(int x = 0; x < views.getLength(); x++){//scan each view if they have our query

				NodeList viewnodes = views.item(x).getChildNodes(); //look for the query node
				for(int y = 0; y < viewnodes.getLength(); y++){
					
					if(viewnodes.item(y) instanceof Element){
						
						if(viewnodes.item(y).getTextContent().equals(query)){
							
							for(int z = y+1; z < viewnodes.getLength(); z++){
								if(viewnodes.item(y) instanceof Element){

									if(viewnodes.item(z).getTextContent().equals(collectionName)){
										Element node = (Element) views.item(x);
										viewfile = node.getAttribute("name");
									}
								}
								if(viewfile != null){
									break;
								}
							}
							
						}
						else{
							break;
						}
					}
					
					if(viewfile != null){
						break;
					}
				}
				if(viewfile != null){
					break;
				}
			}
		}
		return viewfile;
		
	}
	
	/**
	 * delete a reference to a particular view in the metadata
	 * @param viewFilename: the  view filename 
	 */
	public void deleteMeta(String viewFilename){
		//check if file exist first
		
		if(!isExist()){
			buildMetaFile();
		}
		else{
			DocumentBuilder docbuilder = null;
			Transformer transform = null;
			Document meta_doc = null;
			
			try {
				DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
				docbuilder = docfactory.newDocumentBuilder();
			}
			catch(ParserConfigurationException e){
				e.printStackTrace();
			}
			
			meta_doc = docbuilder.newDocument();
			
			String path = "metadata.xml";		
			File xmlfile = new File(path);
			
			try{
				meta_doc = docbuilder.parse(xmlfile);
			}
			catch(Exception e){
				e.printStackTrace();
			}
			
			NodeList views = meta_doc.getElementsByTagName("view");
			
			for(int x = 0; x < views.getLength(); x++){
				Element e = (Element)views.item(x);				
				if(e.getAttribute("name").equals(viewFilename)){					
					Node n = views.item(x);
					n.getParentNode().removeChild(n);
				}
			}
			
			try{
				TransformerFactory tFactory = TransformerFactory.newInstance();
				transform = tFactory.newTransformer();
				transform.setOutputProperty(OutputKeys.INDENT, "yes");
			}
			catch(TransformerConfigurationException e){
				e.printStackTrace();
			}
			
			if(transform != null){
				DOMSource xml_source = new DOMSource(meta_doc);			
				
				String filename = "metadata.xml";
				File xml_file = new File(filename);
				StreamResult xml_doc = new StreamResult(xml_file);
				
				try{
					transform.transform(xml_source, xml_doc);
				}
				catch(TransformerException e){
					e.printStackTrace();
				}
			}
			
		}
	}

	/**
	 * insert new log in the metadata
	 * @param collectionName: name of the collection
	 * @param query: the query used for the transaction
	 * @param viewName: name of the view
	 */
	public void insertMeta(String collectionName, String query, String viewName){
		//check if file exist first
		
		if(!isExist()){
			buildMetaFile();
		}
		else{
			DocumentBuilder docbuilder = null;
			Transformer transform = null;
			Document meta_doc = null;
			
			try {
				DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
				docbuilder = docfactory.newDocumentBuilder();
			}
			catch(ParserConfigurationException e){
				e.printStackTrace();
			}
			
			meta_doc = docbuilder.newDocument();
			
			String path = "metadata.xml";		
			File xmlfile = new File(path);
			
			try{
				meta_doc = docbuilder.parse(xmlfile);
			}
			catch(Exception e){
				e.printStackTrace();
			}
			
			Node root = meta_doc.getFirstChild();
			
			//create view node
			Element viewname = meta_doc.createElement("view");
			viewname.setAttribute("name", viewName );
			
			//create query node
			Element querynode = meta_doc.createElement("query");
			querynode.setTextContent(query);
			viewname.appendChild(querynode);
			
			//create collection node
			Element collnode = meta_doc.createElement("collection");
			collnode.setTextContent(collectionName);
			viewname.appendChild(collnode);
			
			root.appendChild(viewname);
		
			try{
				TransformerFactory tFactory = TransformerFactory.newInstance();
				transform = tFactory.newTransformer();
				transform.setOutputProperty(OutputKeys.INDENT, "yes");
			}
			catch(TransformerConfigurationException e){
				e.printStackTrace();
			}
			
			if(transform != null){
				DOMSource xml_source = new DOMSource(meta_doc);			
				
				String filename = "metadata.xml";
				File xml_file = new File(filename);
				StreamResult xml_doc = new StreamResult(xml_file);
				
				try{
					transform.transform(xml_source, xml_doc);
				}
				catch(TransformerException e){
					e.printStackTrace();
				}
			}
			
		}
		
	}

	/**
	 * check if there are references to the collection in the meta file
	 * @param collectionName: name of the collection
	 * @return: mapping of view filename and query used to build it
	 */
	public Map<String, String> findCollectionMeta(String collectionName){
		//check if file exist first
		Map<String, String> viewMap = new TreeMap<String,String>();
		
		if(!isExist()){
			buildMetaFile();
		}
		else{
			DocumentBuilder docbuilder = null;
			Document new_doc = null;
			
			try {
				DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
				docbuilder = docfactory.newDocumentBuilder();
			}
			catch(ParserConfigurationException e){
				e.printStackTrace();
			}
			
			new_doc = docbuilder.newDocument();
			
			String path = "metadata.xml";		
			File xmlfile = new File(path);
			
			try{
				new_doc = docbuilder.parse(xmlfile);
			}
			catch(Exception e){
				e.printStackTrace();
			}
			
			Node root = new_doc.getFirstChild();
			//System.out.println("root element "+root.getNodeName());
			
			
			NodeList views = root.getChildNodes(); //get all the views
						
			for(int x = 0; x < views.getLength(); x++){//scan each view if they have our query
				//System.out.println("view: " + views.item(x).getNodeName());
				NodeList viewnodes = views.item(x).getChildNodes(); //look for the query node
				for(int y = 0; y < viewnodes.getLength(); y++){
					
					if(viewnodes.item(y) instanceof Element){
						//System.out.println("view child: " + viewnodes.item(y).getNodeName());
						
						
						if(viewnodes.item(y).getTextContent().equals(collectionName)){
							//System.out.println("view child content: " + viewnodes.item(y).getTextContent());
							
							for(int z = 0; z < viewnodes.getLength(); z++){
								if(viewnodes.item(y) instanceof Element){
																		
									if(viewnodes.item(z).getNodeName().equals("query")){
										String value = viewnodes.item(z).getTextContent();	
										//System.out.println("value: " + viewnodes.item(z).getTextContent());
										Element node = (Element) views.item(x);
										String key = node.getAttribute("name");
										//System.out.println("key: " + node.getAttribute("name"));
										viewMap.put(key, value);
									}
								}
								
							}
							
						}
						
					}
					
				}
				
			}
		}
		
		return viewMap;
	}

	

}
